fix: eliminate FOUC on cookie accept and custom font load#4999
fix: eliminate FOUC on cookie accept and custom font load#4999woohyeokk-choi wants to merge 1 commit intofastrepl:mainfrom
Conversation
Remove the isInitialized state from PostHogProvider so the wrapper type stays stable (always PostHogReactProvider in prod) and React never unmounts/remounts children when analytics consent is given. Verified safe against posthog-js v1.367.0 source: all capture/identify calls are no-ops before init() via the __loaded guard. Add font-display: swap to all @font-face rules so custom fonts (Redaction, SF Pro) swap in without blocking render. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
👷 Deploy request for hyprnote pending review.Visit the deploys page to approve it
|
✅ Deploy Preview for char-cli-web canceled.
|
ComputelessComputer
left a comment
There was a problem hiding this comment.
The FOUC fix is correct in diagnosis and the font change is fine to ship. One issue with the PostHog change worth addressing before merge.
The problem: removing the isInitialized wrapper and always rendering PostHogReactProvider fixes the remount flash, but it silently drops mount-time analytics events for returning users with stored consent. The old Fragment → PostHogReactProvider swap was ugly but accidentally gave components a second mount cycle after init — meaning hero_section_viewed, identify on auth callback, and identify on billing refresh all had a chance to fire against an initialized client. Now they fire once, before posthog.init() runs, and are lost.
On compliance: the banner exists to comply with GDPR/CCPA. Always rendering PostHogReactProvider before init() is technically safe from a cookie/data perspective (posthog-js is inert before init()), but the spirit of the consent gate is that no tracking happens before the user accepts. Queuing events that fire before consent and then replaying them after the user accepts would silently track users retroactively — which is the behavior GDPR specifically prohibits. So events that fire before consent should stay dropped.
Suggested fix:
- Keep the stable wrapper (always render
PostHogReactProvider) — fixes FOUC ✅ - Keep
posthog.init()gated on consent — GDPR/CCPA compliant ✅ - For the data loss issue: guard mount-time tracking calls with an
analyticsReadycheck (not justposthogexists), so they only fire after init. Don't replay — just accept that events before consent are intentionally not collected.
The font font-display: swap change is clean and unrelated — happy to see that ship.
Summary
isInitializedstate fromPostHogProviderso the React wrapper type stays stable (PostHogReactProviderin prod with an API key). Previously, accepting cookie consent triggered aFragment → PostHogReactProviderwrapper swap that unmounted and remounted the entire page, causing a brief flash of unstyled content.font-display: swapto all@font-facerules (Redaction, SF Pro) so custom fonts swap in without blocking render.Root cause
PostHogProviderconditionally rendered<>{children}</>or<PostHogReactProvider>based on anisInitializedstate that started asfalse. On consent accept, React saw a component type change and remounted all children — visible as FOUC.Safety verification
Verified against
posthog-jsv1.367.0 source: allcapture()/identify()calls are silent no-ops beforeinit()via the!this.__loadedguard. RenderingPostHogReactProviderwith an uninitialized client sets no cookies, makes no network requests, and queues no events.Test plan
🤖 Generated with Claude Code
Note
Low Risk
Low risk UI/perf changes: adjusts PostHog wrapper rendering and font loading behavior, with limited blast radius beyond analytics initialization timing.
Overview
Prevents a full subtree remount (and resulting FOUC) when analytics consent is toggled by making
PostHogProvideralways renderPostHogReactProviderin production when an API key is present, while guardingposthog.init()to run only once viadidInitRef.Improves perceived loading by adding
font-display: swapto all custom@font-facedeclarations so text renders immediately with fallback fonts and swaps when Redaction/SF Pro are ready.Reviewed by Cursor Bugbot for commit 5258d01. Bugbot is set up for automated code reviews on this repo. Configure here.